#include <stdio.h>
#include <stdlib.h>

#include <png.h>

#include "_osd.h"
#include "_png.h"
#include "_types.h"
#include "window.h"
#include "_window.h"

/* Enables or disables debug output */
#ifdef __DEBUG
#define __D(fmt, args...) fprintf(stderr, "PNG Debug: " fmt, ## args)
#else
#define __D(fmt, args...)
#endif

#define __E(fmt, args...) fprintf(stderr, "PNG Error: " fmt, ## args)

int png_create(FILE *file, image *pngp) {
    __u16 *dst;
    __u8 *alphadst;
    unsigned char *row_pointers[576];
    int r, g, b;
    int x, y;
    png_structp png_ptr;
    png_infop info_ptr;
    png_uint_32 width, height;
    int bit_depth, color_type, interlace_type;
    int pos;
    unsigned char Bpp; // Se for RGB, transforma em RGBA com opacidade maxima em todos os pixels

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (png_ptr == NULL) {
        __E("Failed to create read struct\n");
        return PNG_FAILURE;
    }

    info_ptr = png_create_info_struct(png_ptr);

    if (info_ptr == NULL) {
        __E("Failed to create info struct\n");
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return PNG_FAILURE;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
        fclose(file);
        return PNG_FAILURE;
    }

    png_init_io(png_ptr, file);

    png_read_info(png_ptr, info_ptr);
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
            &interlace_type, int_p_NULL, int_p_NULL);

    png_set_strip_16(png_ptr);
    //png_set_strip_alpha(png_ptr);
    png_set_packing(png_ptr);
    png_set_packswap(png_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_gray_1_2_4_to_8(png_ptr);

    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        Bpp = 4;
    else Bpp = 3;

    for (y = 0; y < height; y++) {
        row_pointers[y] = png_malloc(png_ptr,
                png_get_rowbytes(png_ptr, info_ptr));
    }

    png_read_image(png_ptr, row_pointers);
    png_read_end(png_ptr, info_ptr);

    pngp->bufp = malloc(width * height * 2);
    pngp->w = width;
    pngp->h = height;

    if (pngp->bufp == NULL) {
        __E("Failed to allocate memory for png image\n");
        return PNG_FAILURE;
    }

    dst = pngp->bufp;

    if ((pngp->alphabufp = malloc(width * height)) == NULL) {
        __E("Failed to allocate memory for png attribute buffer\n");
        return PNG_FAILURE;
    }

    alphadst = pngp->alphabufp;

    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
            pos = x * Bpp;
            r = row_pointers[y][pos + 0] * (1 << 5) / (1 << 8);
            g = row_pointers[y][pos + 1] * (1 << 6) / (1 << 8);
            b = row_pointers[y][pos + 2] * (1 << 5) / (1 << 8);
            if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
                *alphadst++ = (unsigned char) (row_pointers[y][pos + 3]);
            } else {
                *alphadst++ = 255;
            }

            dst[x] = b | (g << 5) | (r << 11);
        }

        dst += width;
    }

    for (y = 0; y < height; y++) {
        png_free(png_ptr, row_pointers[y]);
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

    fclose(file);

    return PNG_SUCCESS;
}

/*int png_delete(_simplepng * pngp) {
    free(pngp->bufp);

    return SIMPLEWIDGET_SUCCESS;
}*/
